#pragma once

#include <hash_map>
#include <stack>

#include "NResource.h"
#include "NeroCore\NMemoryManager.h"

namespace Engine
{
template<class T>
class NResourceManager
{
public:
	typedef std::pair<std::string, T*> ResourcePair;
	typedef std::hash_map<std::string, T*> ResourceMap;
	typedef void (*CreateResourceFunction)(T** resource, const unsigned int handle, const std::string& instanceName, const std::string& filePath);

public:
	NResourceManager(CreateResourceFunction s);

	virtual ~NResourceManager();

	void Add(const std::string& instanceName, T* resource);

	void Add(const std::string& instanceName, const std::string& filePath);

	T* operator[](unsigned int handle);

	T* GetResource(unsigned int handle);

	T* GetResource(const std::string& instanceName);

	const ResourceMap& GetResources() const;

	void Remove(unsigned int handle);

	void ClearResources();

protected:
	std::stack<unsigned int> mHandles;
	ResourceMap mResources;
	CreateResourceFunction mCreateResourceFunction;
};

template<class T>
NResourceManager<T>::NResourceManager(CreateResourceFunction s)
	:mCreateResourceFunction(s)
{
}

template<class T>
NResourceManager<T>::~NResourceManager()
{
}

template<class T>
void NResourceManager<T>::Add(const std::string& instanceName,T* resource)
{
	if(resource != NULL)
	{
		mResources.insert(ResourcePair(instanceName, resource));
	}
}

template<class T>
void NResourceManager<T>::Add(const std::string& instanceName, const std::string& filePath)
{
	T* resource = NULL;
	unsigned int handle = 1;
	(*mCreateResourceFunction)(&resource, handle, instanceName, filePath);

	mHandles.push(handle);
	mResources.insert(ResourcePair(instanceName, resource));
}

template<class T>
void NResourceManager<T>::Remove(unsigned int handle)
{
	//ResourceMap::iterator _it = mResources.find(
}

template<class T>
T* NResourceManager<T>::operator[](unsigned int handle)
{
	return mHandles[handle];
}

template<class T>
T* NResourceManager<T>::GetResource(unsigned int handle)
{
	return this->operator[](handle);
}

template<class T>
T* NResourceManager<T>::GetResource(const std::string& instanceName)
{
	ResourceMap::iterator _it = mResources.find(instanceName);
	if(_it != mResources.end())
	{
		return mResources[instanceName];
	}
	return NULL;
}

template<class T>
const std::hash_map<std::string, T*>& NResourceManager<T>::GetResources() const
{
	return mResources;
}

template<class T>
void NResourceManager<T>::ClearResources()
{
	mHandles.clear();
	mResources.clear();
}

}